package com.datasecops.scannerservices.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.krb5.EncryptedData;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * AES加解密工具-- DSM同步
 *
 * @author: SunLingzhi
 * @time: 2022/8/18 17:20
 */
public class AESEncoder {

    private final static String keyEqualWeb = "EEDlp00000000000";

    private static Cipher getCipherFromKey(String sKey, int eMode) {

        int sub = sKey.length();
        StringBuffer keyBuffer = new StringBuffer();
        keyBuffer.append(sKey);

        // 将原始字节数组转换为16位
        if (sub < 16) {
            for (int i = 0; i < 16 - sub; i++) {
                keyBuffer.append("0");
            }
        }

        byte[] raw = null;
        try {
            raw = keyBuffer.toString().getBytes("ASCII");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] b = "0102030405060708".getBytes();
            IvParameterSpec iv = new IvParameterSpec(b);// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(eMode, skeySpec, iv);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } // "算法/模式/补码方式"


        return cipher;
    }

    // 加密
    public static String Encrypt(String sSrc, String sKey) throws Exception {

        int sub = sKey.length();
        StringBuffer keyBuffer = new StringBuffer();
        keyBuffer.append(sKey);

        // 将原始字节数组转换为16位
        if (sub < 16) {
            for (int i = 0; i < 16 - sub; i++) {
                keyBuffer.append("0");
            }
        }

        byte[] raw = keyBuffer.toString().getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
        IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes());

        return new BASE64Encoder().encode(encrypted);
    }


    // 加密
    public static String EncryptV2(String sSrc, String sKey) {

        int sub = sKey.length();
        StringBuffer keyBuffer = new StringBuffer();
        keyBuffer.append(sKey);

        // 将原始字节数组转换为16位
        if (sub < 16) {
            for (int i = 0; i < 16 - sub; i++) {
                keyBuffer.append("0");
            }
        }

        byte[] raw = keyBuffer.toString().getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes());
            return Bit2Hex.bytesToHexString(encrypted);

        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | NoSuchPaddingException | BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } // "算法/模式/补码方式"

        return null;
    }


    // 解密
    public static String Decrypt(String sSrc, String sKey) throws Exception {
        try {

            int sub = sKey.length();
            StringBuffer keyBuffer = new StringBuffer();
            keyBuffer.append(sKey);

            // 将原始字节数组转换为16位
            if (sub < 16) {
                for (int i = 0; i < 16 - sub; i++) {
                    keyBuffer.append("0");
                }
            }

            byte[] raw = keyBuffer.toString().getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original);
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    // 解密
    public static String DecryptV2(String sSrc, String sKey) {
        try {
            int sub = sKey.length();
            StringBuffer keyBuffer = new StringBuffer();
            keyBuffer.append(sKey);

            // 将原始字节数组转换为16位
            if (sub < 16) {
                for (int i = 0; i < 16 - sub; i++) {
                    keyBuffer.append("0");
                }
            }

            byte[] raw = keyBuffer.toString().getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = Bit2Hex.hexStringToBytes(sSrc);
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original);
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    public static String DecryptV2WithKey(String sSrc) {
        return DecryptV2(sSrc, keyEqualWeb);
    }

    public static String EncryptV2WithKey(String sSrc) {
        return EncryptV2(sSrc, keyEqualWeb);
    }


    public static byte[] shortToByteArray(int valor) {
        byte[] result = new byte[2];
        for (int i = 0; i < result.length; i++) {
            result[1 - i] = (byte) (valor & 0xFF);
            valor = valor >> 8;
        }
        return result;
    }

    public static boolean encryptFile(String src, String des, String sKey) {

        InputStream inEn = null;
        OutputStream outEn = null;

        try {
            inEn = new FileInputStream(src);
            outEn = new FileOutputStream(des);
            AESEncoder.encrypt(inEn, outEn, sKey);
            inEn.close();
            outEn.close();
        } catch (ShortBufferException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        } catch (GeneralSecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public static void encrypt(InputStream in, OutputStream out, String sKey) throws IOException, ShortBufferException, GeneralSecurityException {

        Cipher cipher = getCipherFromKey(sKey, Cipher.ENCRYPT_MODE);
        if (null == cipher) {
            return;
        }

        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        byte[] inBytes = new byte[blockSize];
        byte[] outBytes = new byte[outputSize];
        byte[] appendAllBytes = new byte[blockSize];
        byte[] appendBytes = new byte[blockSize];
        int inLength = 0;
        int length1 = in.available();
        boolean more = true;
        int yushu = length1 % 16;

        if (yushu == 0) {
            for (int i = 0; i < 16; i++) {
                appendAllBytes[i] = new Integer(16).byteValue();
            }
            out.write(shortToByteArray(length1 + blockSize));
        } else {
            int N = blockSize - yushu;
            out.write(shortToByteArray(length1 + N));
        }

        while (more) {
            inLength = in.read(inBytes);
            if (inLength == blockSize) {
                int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
                out.write(outBytes, 0, outLength);
            } else {
                more = false;
            }
        }
        if (inLength > 0 && inLength < blockSize) {// 不足16字节的数据块按照PKCS5方式补充，缺少N个字节则把缺少的N个字节都以N来填充
            int N = blockSize - inLength;
            for (int M = inLength; M < blockSize; M++) {
                inBytes[M] = new Integer(N).byteValue();
            }
            outBytes = cipher.doFinal(inBytes, 0, inLength);
            out.write(outBytes);
        } else if (inLength == 0) {// 如果正好是16位，则增加一个全部字节都填充为16的数据块
            int outLength = cipher.doFinal(appendBytes, 0, blockSize, outBytes);
            out.write(outBytes, 0, outLength);
        }
        out.flush();
    }

    public static void decrypt(InputStream in, OutputStream out, String sKey) throws IOException, ShortBufferException, GeneralSecurityException {
        Cipher cipher = getCipherFromKey(sKey, Cipher.DECRYPT_MODE);
        if (null == cipher) {
            return;
        }

        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        byte[] inBytes = new byte[blockSize];
        byte[] outBytes = new byte[outputSize];
        byte[] dataLength = new byte[2];
        int inLength = 0;
        boolean more = true;
        in.read(dataLength);// 将数据包的长度读入到byte数组中
        while (more) {
            inLength = in.read(inBytes);
            if (inLength == blockSize) {
                int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
                out.write(outBytes, 0, outLength);
            } else {
                more = false;
            }
        }
        if (inLength > 0) {
            outBytes = cipher.doFinal(inBytes, 0, inLength);
        } else {
            outBytes = cipher.doFinal();
        }
        out.write(outBytes);
        out.flush();
    }

    public static void main(String[] args) {
        String s = EncryptV2WithKey("123.4567a");
        String s2  = DecryptV2WithKey("95ec5c3786c28e6d87a13c2db34fce28");
        String s1  = DecryptV2WithKey(s2);
        System.out.println(s);
        System.out.println(s1);
        System.out.println(s2);
        //813304833b13f6070c5add23f6c984e2

    }

}
